home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / basics / show movie / moviestuff.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  31.1 KB  |  994 lines

  1. /*
  2.     File:        MovieStuff.c
  3.  
  4.     Contains:        movie handling routines
  5.                             This handles all the clever movie stuff.
  6.                             - Sets up movie windows
  7.                             - Tears down movie windows
  8.                             - handles updates and events
  9.                             - handles slaving, altering playback speed, looping etc
  10.                             
  11.     Written by: Jason Hodges-Harris & Don Swatman    
  12.  
  13.     Copyright:    Copyright © 1995-1999 by Apple Computer, Inc., All Rights Reserved.
  14.  
  15.                 You may incorporate this Apple sample source code into your program(s) without
  16.                 restriction. This Apple sample source code has been provided "AS IS" and the
  17.                 responsibility for its operation is yours. You are not permitted to redistribute
  18.                 this Apple sample source code as "Apple sample source code" after having made
  19.                 changes. If you're going to re-distribute the source, we require that you make
  20.                 it clear in the source that the code was descended from Apple sample source
  21.                 code, but that you've made changes.
  22.  
  23.     Change History (most recent first):
  24.                 8/17/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  25.                 
  26.  
  27. */
  28.  
  29. #include <Memory.h>
  30. #include <TextUtils.h>
  31. #include <Movies.h>
  32.  
  33. #include "MovieStuff.h"
  34. #include "WindStuff.h"
  35.  
  36. //==============================================
  37. //  CallBackInfoType
  38. //
  39. // This structure is used to store QuickTime 
  40. // call backs and any data they require.
  41. // - It has a several parameters at the front,
  42. //   then a variable size record at the end. It also
  43. //   needs the parameters used in CallMeWhen
  44. // - It's size is:
  45. //      "sizeof(CallBackInfoType) + callBackDataSize - sizeof(long)"
  46. // - Data should not contain the only reference
  47. //   to other handles, as it can't dispose of them
  48. // - It forms a linked list. Any new items are
  49. //   added to the front.
  50. // - It should be passed in the call backs 
  51. //   reference field.
  52. //==============================================
  53.  
  54. struct CallBackInfoType
  55. {
  56.     struct CallBackInfoType **hNextCallBackInfo; // Next in the list
  57.     
  58.     QTCallBack actualCallBack;    // the call back
  59.     WindowPtr  pParentWindow;     // parent window of the movie
  60.     long       param1;            // Used in "CallMeWhen"
  61.     long       param2;            // Used in "CallMeWhen"
  62.     long       param3;            // Used in "CallMeWhen"
  63.     long       callBackDataSize;  // Size of the data attached on the end
  64.     long       callBackDataStart; // where the data starts
  65. };
  66.  
  67. typedef struct CallBackInfoType CallBackInfoType,
  68.     *CallBackInfoPtr, **CallBackInfoHdl;
  69.  
  70. //==============================================
  71. //  DocMovieInfoType
  72. //
  73. // Used to hold information about a movie within
  74. // a window
  75. // - It should be attached to the windows RefCon
  76. //==============================================
  77.  
  78. struct DocMovieInfoType
  79. {
  80.         FSSpec          movieFileSpec;  // movies File Spec
  81.         MovieController movieControls;    // standard movie controller
  82.         Movie           actualMovie;        // the Movie itself!
  83.         Boolean         movieAutoClose; // True if the window closes after movie finishes
  84.         TimeBase              moviesTimeBase;
  85.         TimeScale              moviesTimeScale;
  86.         CallBackInfoHdl hFirstCallBackData; // Handle to first item of the call back info list
  87.         WindowPtr       pSlaveWind;     // WindowPtr of this movies slave
  88. };
  89.  
  90. typedef struct DocMovieInfoType DocMovieInfoType,
  91.     *DocMovieInfoPtr, **DocMovieInfoHndl;
  92.  
  93. //==============================================
  94. // Global Stuff, init and tear down             
  95. //==============================================
  96.  
  97. // Prototypes of functions  used in UPPs
  98. pascal void StartMovieCB(QTCallBack myCallBack,long ref);
  99. pascal void AlterRate( QTCallBack myCallBack,long ref);
  100. pascal void AlterMasterOffset( QTCallBack myCallBack,long ref);
  101.  
  102. // Global UPPs
  103. QTCallBackUPP        gStartMovieCBUpp;
  104. QTCallBackUPP        gAlterRateUpp;
  105. QTCallBackUPP        gAlterMasterOffsetUpp;
  106.  
  107. //----------------------------------------------
  108. // InitMovieGlobals
  109. //
  110. // Init's any globals used in MovieStuff
  111. // i.e. the UPPs             
  112. //----------------------------------------------
  113. void InitMovieGlobals(void)
  114. {
  115.     gStartMovieCBUpp = nil;
  116.     gAlterRateUpp    = nil;
  117.     gAlterMasterOffsetUpp = nil;
  118.  
  119. //    Create routine descriptor for "StartMovieCB" QT callback routine
  120.     gStartMovieCBUpp = NewQTCallBackProc(StartMovieCB);
  121.  
  122. //    Create routine descriptor for "AlterRate" QT callback routine
  123.     gAlterRateUpp = NewQTCallBackProc(AlterRate);
  124.  
  125. //    Create routine descriptor for "AlterMasterOffset" QT callback routine
  126.     gAlterMasterOffsetUpp = NewQTCallBackProc(AlterMasterOffset);
  127.  
  128. }
  129.  
  130. //----------------------------------------------
  131. // KillMovieGlobals
  132. //
  133. // Removes the UPPs             
  134. //----------------------------------------------
  135. void KillMovieGlobals(void)
  136. {
  137. // Clear the Universal Proc Pointers
  138. //    You don't need to do this as quiting the app will do it for you,
  139. //    however, I have this thing about neatness.    
  140.     if (gStartMovieCBUpp)
  141.         DisposeRoutineDescriptor(gStartMovieCBUpp);
  142.     if (gAlterRateUpp)
  143.         DisposeRoutineDescriptor(gAlterRateUpp);
  144.     if (gAlterMasterOffsetUpp)
  145.         DisposeRoutineDescriptor(gAlterMasterOffsetUpp);
  146.         
  147. }
  148.  
  149.  
  150. //==============================================
  151. //
  152. // Error Reporting
  153. //
  154. //==============================================
  155.  
  156. //----------------------------------------------
  157. // Report Error
  158. //
  159. // If an error occurs, Uses DebugStr to send out
  160. // some text passed to it, then the error number
  161. //----------------------------------------------
  162.  
  163. void ReportError( Str255 errText, OSErr theErr );
  164. void ReportError( Str255 errText, OSErr theErr )
  165. {
  166.     Str255 errorStr;
  167.  
  168. // Check there is an error
  169.     if (theErr)
  170.     {
  171. // convert theErr number to text
  172.         NumToString(theErr,errorStr);
  173.  
  174. // if there is error text then displat it
  175.         if (errText != "\p")
  176.             DebugStr(errText);
  177. // Display error number
  178.         DebugStr(errorStr);
  179.     }
  180. }
  181.  
  182. //----------------------------------------------
  183. // GetAndReportError
  184. //
  185. //   Checks GetMoviesError and reports error if
  186. // needed
  187. //----------------------------------------------
  188. OSErr GetAndReportError( Str255 errText );
  189. OSErr GetAndReportError( Str255 errText )
  190. {
  191.     OSErr  theErr;
  192.  
  193.     theErr = GetMoviesError();       // Get Movies error number
  194.     ReportError( errText, theErr );  // And report it
  195.     return(theErr);                  // Oh yeh, return it to the caller
  196. }
  197.  
  198. //==============================================
  199. //
  200. // Call Back info stuff
  201. //
  202. // Following routines handle the CallBackInfoHdl
  203. // structure.
  204. //==============================================
  205.  
  206. //----------------------------------------------
  207. // AddNewCallBackInfo
  208. //
  209. //  Creates a new "CallBackInfoHdl", intialises and
  210. //    returns it
  211. // - It puts "pWindow" and "theCallBack" into the structure
  212. // - It appends "dataSize" bytes of data from "pDataStart"
  213. //   on to the end of the structure 
  214. //----------------------------------------------
  215.  
  216. CallBackInfoHdl AddNewCallBackInfo( WindowPtr  pWindow,
  217.                                                                         QTCallBack theCallBack,
  218.                                                                         Ptr        pDataStart,
  219.                                                                         long       dataSize,
  220.                                                                         long       param1,
  221.                                                                         long       param2,
  222.                                                                         long       param3
  223.                                                                     );
  224. CallBackInfoHdl AddNewCallBackInfo( WindowPtr  pWindow,
  225.                                                                         QTCallBack theCallBack,
  226.                                                                         Ptr        pDataStart,
  227.                                                                         long       dataSize,
  228.                                                                         long       param1,
  229.                                                                         long       param2,
  230.                                                                         long       param3
  231.                                                                     )
  232. {
  233.     CallBackInfoHdl  hNewCBInfo = nil;  // the new call back info record
  234.     DocMovieInfoHndl hDocMovieInfo;
  235.     long newSize;   // Size of hNewCBInfo and the data added to it
  236.     
  237. // Calculate how big the block needs to be
  238.     newSize = sizeof(CallBackInfoType) + dataSize - sizeof(long);
  239.  
  240. // Create the call back data item
  241.     hNewCBInfo = (CallBackInfoHdl) NewHandle (newSize);
  242.  
  243. // Check that we actualy did create it!
  244.     if (hNewCBInfo)
  245.     {
  246.  
  247. // Setup the structure
  248.  
  249.         (**hNewCBInfo).hNextCallBackInfo = nil;
  250.         (**hNewCBInfo).actualCallBack    = theCallBack;
  251.         (**hNewCBInfo).pParentWindow     = pWindow;
  252.         (**hNewCBInfo).param1 = param1;
  253.         (**hNewCBInfo).param2 = param2;
  254.         (**hNewCBInfo).param3 = param3;
  255.         (**hNewCBInfo).callBackDataSize  = 0;
  256.  
  257. // Add in the data (if there is any)
  258.  
  259.         if (dataSize && pDataStart)
  260.         {
  261.             (**hNewCBInfo).callBackDataSize  = dataSize;
  262.             BlockMove( pDataStart, &((**hNewCBInfo).callBackDataStart), dataSize);
  263.         }
  264.  
  265. // Now, link it into the window data structure (attach it to the front of the chain)
  266.  
  267.         hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon ( pWindow );
  268.         (**hNewCBInfo).hNextCallBackInfo     = (**hDocMovieInfo).hFirstCallBackData;
  269.         (**hDocMovieInfo).hFirstCallBackData = hNewCBInfo;
  270.     }
  271.     
  272.     return( hNewCBInfo );
  273. }
  274.  
  275. //----------------------------------------------
  276. //  RemoveCallBackInfo
  277. //
  278. //  Scans down the CallBackInfoHdl chain and disposes
  279. // of each one
  280. //----------------------------------------------
  281.  
  282. void RemoveCallBackInfo ( CallBackInfoHdl hFirstItem );
  283. void RemoveCallBackInfo ( CallBackInfoHdl hFirstItem )
  284. {
  285.     CallBackInfoHdl  hNextCBInfo;
  286.     CallBackInfoHdl  hDisposeData;
  287.  
  288.     if (hFirstItem)
  289.     {
  290. // Scan down the chain of items, disposing as we go
  291.         hNextCBInfo = hFirstItem;
  292.         while (hNextCBInfo)
  293.         {
  294.             hDisposeData = hNextCBInfo;
  295.             hNextCBInfo  = (**hNextCBInfo).hNextCallBackInfo;
  296.     
  297.         // Dispose of the call back
  298.             DisposeCallBack( (**hDisposeData).actualCallBack );
  299.  
  300.         // Dispose of the call back info block
  301.             DisposeHandle( (Handle) hDisposeData);
  302.         }
  303.     }
  304.         
  305. }
  306.  
  307. //----------------------------------------------
  308. //  GetDataFromCBInfo
  309. //
  310. // Extracts the data from a CallBackInfoHdl and
  311. // moves the data into it. Checks the stored structure
  312. // is smaller than requested size. Ideally they should
  313. // be the same size.
  314. //----------------------------------------------
  315.  
  316. Boolean GetDataFromCBInfo ( CallBackInfoHdl  hCallBackInfo,
  317.                                                         Ptr    pData,
  318.                                                         long   maxDataSize   );
  319. Boolean GetDataFromCBInfo ( CallBackInfoHdl  hCallBackInfo,
  320.                                                         Ptr    pData,
  321.                                                         long   maxDataSize   )
  322. {
  323.     Boolean isOk = false;
  324.     
  325. // Check that we have a call back,
  326. //                     and we have some where to put the data,
  327. //                         and it's bigger than 0
  328.     if (hCallBackInfo && pData && maxDataSize)
  329.  
  330. // Check the call back data is smaller than the new structure 
  331.         if ( (**hCallBackInfo).callBackDataSize  <= maxDataSize)
  332.         {
  333.  
  334. // Move the data to pData
  335.             BlockMove ( &((**hCallBackInfo).callBackDataStart),
  336.                                     pData,
  337.                                     (**hCallBackInfo).callBackDataSize );
  338.             isOk = true;
  339.         }
  340.     return ( isOk );
  341. }
  342.  
  343. //----------------------------------------------
  344. //  IsMoviePlaying
  345. //
  346. // Find out if any movie is playing
  347. //----------------------------------------------
  348.  
  349. Boolean IsMoviePlaying (void)
  350. {
  351.     DocMovieInfoHndl hDocMovieInfo; // The movie we're checkings info
  352.     Boolean movieLive = false; // set to true if there is a live window
  353.     short   windCount;
  354.     
  355. // Scan the window list until we've found a live window
  356.     for (windCount = 0;(windCount < kMaxWindows) && !movieLive; windCount++ )
  357. // If this window is open
  358.         if (gTheWinds[windCount])
  359.             {
  360. // Get information about the movie
  361.                 hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (gTheWinds[windCount]);
  362.  
  363. // Use IsMovieDone to see if it's still running
  364.                 if (!IsMovieDone((**hDocMovieInfo).actualMovie) )
  365.                     movieLive = true;
  366.             }
  367.     return (movieLive);
  368. }
  369.  
  370. //----------------------------------------------
  371. // UpdateMovieWindow
  372. //----------------------------------------------
  373. void UpdateMovieWindow (  WindowPtr pWindow   )
  374. {
  375. // Get the movie from the ref con and update it. Easy.
  376.     UpdateMovie( (**(DocMovieInfoHndl)GetWRefCon( pWindow )).actualMovie);
  377. }
  378.  
  379. //----------------------------------------------
  380. // Load a movie into memory
  381. //
  382. //  Use standard file to get and load a movie
  383. //----------------------------------------------
  384. void    LoadOneMovie( DocMovieInfoHndl hDocMovieInfo );
  385. void    LoadOneMovie( DocMovieInfoHndl hDocMovieInfo )
  386. {
  387.     Movie         myNewMovie = nil;   // The new movie
  388.     StandardFileReply    newMovieFile;   // Standard File Reply about the  movies file
  389.     Str255        myMovieName;        // The Movies name
  390.     OSErr         error;
  391.     SFTypeList    myTypes = {MovieFileType}; // File types we want Standard File to get
  392.     short         myMovieResFile;     // Movie files ref number
  393.     short         myMovieResID = 0;   // Load the first movie res
  394.     Boolean       movieChanged;       // Set to true if movie was changed durring 
  395.                                                                         // loading to resolve references
  396.         
  397. // Use standard file to get the fsSpec etc.
  398.     StandardGetFilePreview(nil,1,myTypes,&newMovieFile);
  399.     if (newMovieFile.sfGood)
  400.     {
  401. // Open the movie file
  402.         error = OpenMovieFile( &newMovieFile.sfFile, &myMovieResFile, fsRdPerm);
  403.         if (error==noErr)
  404.         {
  405. // Store the file spec
  406.             (**hDocMovieInfo).movieFileSpec = newMovieFile.sfFile;
  407.  
  408. // Move Movie data in to memory
  409.             error = NewMovieFromFile( &myNewMovie, myMovieResFile, &myMovieResID,
  410.                                       myMovieName, newMovieActive, &movieChanged);
  411.  
  412. // Close the file as we succeded in opening it
  413.             CloseMovieFile (myMovieResFile);
  414.         }
  415.     }
  416.     (**hDocMovieInfo).actualMovie =    myNewMovie; // Return myNewMovie
  417. }
  418.  
  419. //----------------------------------------------
  420. // ServiceMovieTasks
  421. //
  422. // Used to Handle the null event. You need to handle
  423. // this to make the movie play!
  424. // - First it sees if the movie controller has an event
  425. // - Scans the window list looking for movies
  426. // - If the movie has finished then close it if the
  427. //   flags are set that way
  428. // - If any movies are active, then call MoviesTask
  429. //   to make them play
  430. // - Finally return true if the event was handled by the
  431. //   movie controller
  432. //----------------------------------------------
  433. Boolean ServiceMovieTasks ( WindowPtr pWindow, const EventRecord *theEvent )
  434. {
  435. #pragma unused ( pWindow )
  436.  
  437.     Boolean doneProccessing = false;  // goes to true if MCIsPlayerEvent handles event
  438.     DocMovieInfoHndl hDocMovieInfo;   // Current windows movie info
  439.     short   windCount;
  440.     Boolean needMovieTasks = false;   // Goes true if there is a movie running
  441.     Boolean moviePlaying;
  442.     
  443. // Scan window list
  444.     for (windCount = 0;windCount < kMaxWindows; windCount++ )
  445.         if (gTheWinds[windCount])
  446.             {
  447. // Get movie information for this window
  448.                 hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (gTheWinds[windCount]);
  449.  
  450. // Handle any events to this windows movie controller if it's got one
  451.                 if (!doneProccessing)
  452.                     if ((**hDocMovieInfo).movieControls)
  453.                         if (MCIsPlayerEvent((**hDocMovieInfo).movieControls, theEvent))
  454.                             doneProccessing = true;
  455.     
  456. // Next bit checks to see if a window has finished playing (by using
  457. // IsMovieDone) and closes it if auto close has been set for it
  458.                 moviePlaying = !IsMovieDone((**hDocMovieInfo).actualMovie);
  459.                 if (   (**hDocMovieInfo).movieAutoClose && (!moviePlaying) )
  460.                     CloseOurWindow( windCount );
  461.                 else
  462.                     if (moviePlaying)
  463.                         needMovieTasks = true; // Hey there's a movie running
  464.             }
  465.  
  466. // If we have an active movie, then service all movies
  467.     if (needMovieTasks)
  468.         MoviesTask(nil,0);
  469.  
  470.     return ( doneProccessing );    
  471. }
  472.  
  473. //----------------------------------------------
  474. //  CloseMovieWindow
  475. //
  476. // Close a movie window and destroys associated
  477. // structures. If this is a Master window,
  478. // sets "*pSlaveWindow" to the slave WindowPtr
  479. //----------------------------------------------
  480. OSErr CloseMovieWindow( WindowPtr pWindow,
  481.                                                 WindowPtr *pSlaveWindow )
  482. {
  483.     DocMovieInfoHndl hDocMovieInfo;
  484.     
  485.     *pSlaveWindow = nil;
  486.  
  487. // Get movie structure
  488.     hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon(pWindow);
  489.  
  490.     if (hDocMovieInfo)
  491.     {
  492. // Set the slave WindowPtr
  493.         *pSlaveWindow = (**hDocMovieInfo).pSlaveWind;
  494.  
  495. // dispose movie
  496.         DisposeMovie((**hDocMovieInfo).actualMovie);
  497.     
  498. // dispose of the controller if it exists
  499.         if ((**hDocMovieInfo).movieControls)
  500.             DisposeMovieController ( (**hDocMovieInfo).movieControls );
  501.     
  502. // dispose of call back structures
  503.         RemoveCallBackInfo ( (**hDocMovieInfo).hFirstCallBackData );
  504.         
  505. // dispose movie structure
  506.         DisposeHandle( (Handle)hDocMovieInfo );
  507.     }
  508.     return ( noErr );
  509. }
  510.  
  511. //----------------------------------------------
  512. //   OpenMovieWindow
  513. //
  514. // - Opens a movie
  515. // - Creates and initialises the windows movie
  516. //   structure "DocMovieInfoHndl"
  517. // - Creates (if wanted) a movie controller
  518. // - Sizes the window to fit the movie and controller
  519. // - Shows the window
  520. //----------------------------------------------
  521. OSErr OpenMovieWindow ( WindowPtr pWindow,
  522.                                                 Boolean   doesAutoClose,
  523.                                                 Boolean   hasControler  )
  524. {
  525.     OSErr theErr = noErr;
  526.     DocMovieInfoHndl hDocMovieInfo = nil; // new window movie information
  527.     Rect moviesRect;   // Size of the movie
  528.     Rect newWindRect;  // New Windows rect (movie + Controllers rect)
  529.     
  530.     if (!pWindow)
  531.     {  // Error !!!!
  532.         DebugStr("\pHey, this window doesn't exists!!");
  533.         theErr = userCanceledErr;  // Should be something more appropriate
  534.     }
  535.     else
  536.     {
  537.  
  538. // allocate new movie doc structure
  539.         hDocMovieInfo = (DocMovieInfoType**) NewHandle (sizeof(DocMovieInfoType));
  540.         if (hDocMovieInfo == nil)
  541.         { // Error !!!!
  542.             DebugStr("\pError allocating doc handle");
  543.             theErr = userCanceledErr;  // Should be something more appropriate
  544.         }
  545.         else
  546.         {
  547. // Set up the hDocMovieInfo record
  548.             (**hDocMovieInfo).movieAutoClose = doesAutoClose;
  549.             (**hDocMovieInfo).hFirstCallBackData  = nil;
  550.             (**hDocMovieInfo).movieControls = nil;
  551.             (**hDocMovieInfo).actualMovie   = nil;
  552.             (**hDocMovieInfo).pSlaveWind    = nil;
  553.             
  554. // set window refcon to movie doc handle
  555.             SetWRefCon( pWindow, (long)hDocMovieInfo );
  556.             SetPort(pWindow);
  557.                     
  558. // load movie refs into doc structure
  559.             LoadOneMovie ( hDocMovieInfo );
  560.             if ((**hDocMovieInfo).actualMovie == nil)
  561.             { // Cancel button pressed or Error !!!!
  562.                 theErr = userCanceledErr;  // Should be something more appropriate
  563.                 return(theErr);
  564.             }
  565.             else
  566.             {
  567. // get timebase from movie
  568.                 (**hDocMovieInfo).moviesTimeBase = GetMovieTimeBase((**hDocMovieInfo).actualMovie);
  569.                 theErr = GetAndReportError( "\pError!! GetMovieTimeBase");
  570.  
  571. // get timescale from movie
  572.                 if (!theErr)
  573.                 {
  574.                     (**hDocMovieInfo).moviesTimeScale = GetMovieTimeScale((**hDocMovieInfo).actualMovie);
  575.                     theErr = GetAndReportError( "\pError!! Getting movie time scale");
  576.                 }
  577.  
  578.                 if (!theErr)
  579.                     if (!hasControler)
  580.                     {
  581.     // Don't want a controller, so just
  582.         // Get movies rect as this is the size of the window
  583.                         GetMovieBox((**hDocMovieInfo).actualMovie, &newWindRect);
  584.                     }
  585.                     else
  586.                     {
  587.     // We want a movie controller so create it beneath the movie
  588.         // Get the movies rect as this is the size we want to put it in
  589.                         GetMovieBox((**hDocMovieInfo).actualMovie, &moviesRect);
  590.     
  591.         //Create a controller and put below the movie. as moviesRect is the size of the movie,
  592.         // the controller will fall outside the rect
  593.                         (**hDocMovieInfo).movieControls = NewMovieController ( (**hDocMovieInfo).actualMovie,
  594.                                                                                                                                      &moviesRect,
  595.                                                                                                                                      mcTopLeftMovie);
  596.                         if ((**hDocMovieInfo).movieControls == nil)
  597.                         { // Failed to create controller Error !!!!
  598.                             theErr = userCanceledErr;  // Should be something more appropriate
  599.                             return(theErr);
  600.                         }
  601.                         else
  602.                         {
  603.     // Get movieControllers rect. Because it is attached the movie, it will return
  604.     // the controller and movies size
  605.                             theErr = MCGetControllerBoundsRect((**hDocMovieInfo).movieControls, &newWindRect);
  606.                         }
  607.                     }
  608.  
  609.                 if (!theErr)
  610.                 {
  611.     // Size the window to fit the movie and controller
  612.                     SizeWindow( pWindow,newWindRect.right, newWindRect.bottom,true);
  613.                 }
  614.             }
  615.         }
  616.     }
  617.     
  618.     return ( theErr );
  619. }
  620.  
  621. //==============================================
  622. // The time base call back procs
  623. //==============================================
  624.  
  625. //----------------------------------------------
  626. //   AlterMasterOffset
  627. //
  628. // QuickTime callback used to set the SetTimeBaseValue.
  629. // - Can be used to make the movie loop.
  630. // - Takes a value in seconds in the data of
  631. //   the CallBackInfoHdl passed in "ref"
  632. //----------------------------------------------
  633.  
  634. pascal void AlterMasterOffset(QTCallBack myCallBack,long ref)
  635. {
  636.     DocMovieInfoHndl hDocMovieInfo;
  637.     WindowPtr pWindow;
  638.     TimeValue newTimeValue; // Where we want to move to
  639.     OSErr     theErr;
  640.  
  641. // Extract where we want to move to from (CallBackInfoHdl)ref
  642.     if (GetDataFromCBInfo( ( CallBackInfoHdl)ref,
  643.                                                  (Ptr) &newTimeValue, sizeof ( TimeValue ) ))
  644.     {
  645.         pWindow = (**(CallBackInfoHdl)ref).pParentWindow;  // Get the parent window
  646.         hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon ( pWindow ); // Get the movie info
  647. // Move our position in the movie
  648.         SetTimeBaseValue ( (**hDocMovieInfo).moviesTimeBase,
  649.                                              newTimeValue,
  650.                                              (**hDocMovieInfo).moviesTimeScale);
  651. // Finally must reschedule the call back so that it happens again
  652.         theErr = CallMeWhen ( myCallBack,
  653.                                                     gAlterMasterOffsetUpp, ref,
  654.                                                     (**(CallBackInfoHdl)ref).param1,
  655.                                                     (**(CallBackInfoHdl)ref).param2,
  656.                                                     (**(CallBackInfoHdl)ref).param3);
  657.     }
  658. }
  659.  
  660. //----------------------------------------------
  661. //   AlterRate
  662. //
  663. // QuickTime callback used to set the movies rate.
  664. // - Alters the speed of playback.
  665. // - Takes a value in the data of the CallBackInfoHdl
  666. //   passed in "ref"
  667. //----------------------------------------------
  668.  
  669. pascal void AlterRate( QTCallBack myCallBack,long ref)
  670. {
  671. #pragma unused ( myCallBack )
  672.  
  673.     DocMovieInfoHndl hDocMovieInfo;
  674.     WindowPtr pWindow;
  675.     long      newMovieRate;
  676.  
  677. // Extract the new speed we want the movie to run at
  678.     if (GetDataFromCBInfo ( ( CallBackInfoHdl)ref, (Ptr) &newMovieRate, sizeof ( long ) ))
  679.     {
  680.         pWindow = (**(CallBackInfoHdl)ref).pParentWindow;  // Get the parent window
  681.         hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon ( pWindow ); // Get the movie info
  682.  
  683.  
  684. // Change the movies rate
  685.         SetMovieRate((**hDocMovieInfo).actualMovie, newMovieRate);
  686.     }
  687.  
  688.     return;
  689. }
  690.  
  691. //----------------------------------------------
  692. //   StartMovieCB
  693. //
  694. // QuickTime callback used to start a movie.
  695. // - Takes a value (Movie) in the data of the CallBackInfoHdl
  696. //   passed in "ref" which is the movie you want to start.
  697. //----------------------------------------------
  698.  
  699.  
  700. pascal void StartMovieCB(QTCallBack myCallBack,long ref)
  701. {
  702. #pragma unused ( myCallBack )
  703.  
  704.     Movie movieToStart;
  705.         
  706.     if (GetDataFromCBInfo ( ( CallBackInfoHdl)ref, (Ptr) &movieToStart, sizeof ( Movie ) ))
  707.     {
  708.         SetMovieRate(movieToStart,65536);
  709.     }
  710. }
  711.  
  712. //==============================================
  713. // Set up the various options
  714. //==============================================
  715.  
  716. //----------------------------------------------
  717. // SetupMovieRate
  718. //
  719. // - Sets up the call backs to change the play back speed
  720. //   of the movie.
  721. // - "delayBeforeChange" gives the time in seconds when
  722. //   the first speed change happens or a constant that
  723. //   tells it to change at 1/3 (& 2/3) of the movies 
  724. //   duration.
  725. //----------------------------------------------
  726.  
  727. OSErr SetupMovieRate( WindowPtr pWindow,  short delayBeforeChange  )
  728. {
  729.     OSErr            theErr = noErr;
  730.     QTCallBack             theNewCallBack;     // Call Back
  731.     long                     theCallBackOffset;  // When we want to change the rate
  732.     TimeValue               theMovieLen;        // Length of the movie
  733.     DocMovieInfoHndl hDocMovieInfo;      // Info about the windows movie
  734.     CallBackInfoHdl  hTempCallBackInfo;  // Call back information
  735.     long             newMovieRate;       // What the new rate will be
  736.  
  737.     hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (pWindow);
  738.     if (hDocMovieInfo != nil)
  739.     {
  740. // Set up the time base value
  741.         SetTimeBaseValue( (**hDocMovieInfo).moviesTimeBase,
  742.                                             0,
  743.                                             (**hDocMovieInfo).moviesTimeScale);
  744.  
  745.         
  746. // If we're changing by a thirds, we need the movie's length
  747.         if (delayBeforeChange == kOneThird)
  748.             theMovieLen  = GetMovieDuration((**hDocMovieInfo).actualMovie);
  749.  
  750. // ---- First call back - slow playback rate to x2 normal -----
  751.  
  752. // Work out length of delay before callbacks start
  753.         if (delayBeforeChange == kOneThird)
  754.             theCallBackOffset = theMovieLen*0.3333;
  755.         else
  756.             theCallBackOffset = delayBeforeChange * (**hDocMovieInfo).moviesTimeScale;
  757.  
  758. // Create a new call back
  759.         theNewCallBack = NewCallBack((**hDocMovieInfo).moviesTimeBase,callBackAtTime);
  760.  
  761.         newMovieRate = 131072;        // speed up rate to x2 normal
  762.  
  763. // Put the call back into call back chain ( and append newMovieRate )
  764.         hTempCallBackInfo = AddNewCallBackInfo( pWindow,
  765.                                                                                         theNewCallBack,
  766.                                                                                         (Ptr)&newMovieRate, sizeof ( long ),
  767.                                                                                         triggerTimeFwd,
  768.                                                                                         theCallBackOffset,
  769.                                                                                         (**hDocMovieInfo).moviesTimeScale  );
  770.  
  771. // Attach the call back to the movie's time structures
  772.         theErr = CallMeWhen ( theNewCallBack,
  773.                                                         gAlterRateUpp,
  774.                                                         (long)hTempCallBackInfo,
  775.                                                         (**hTempCallBackInfo).param1,
  776.                                                         (**hTempCallBackInfo).param2,
  777.                                                         (**hTempCallBackInfo).param3 );
  778.         if (theErr)
  779.             ReportError( "\pError !! CallMeWhen", theErr );
  780.         else
  781.         {
  782.  
  783. // ---  Second call back - slow playback rate to 1/2 normal ----
  784.  
  785. // Work out length of delay before callbacks start
  786.             if (delayBeforeChange == kOneThird)
  787.                 theCallBackOffset = theMovieLen*0.6666;
  788.             else
  789.                 theCallBackOffset = (2 * delayBeforeChange) * (**hDocMovieInfo).moviesTimeScale;
  790.     
  791. // Create a new call back
  792.             theNewCallBack = NewCallBack((**hDocMovieInfo).moviesTimeBase,callBackAtTime);
  793.     
  794.             newMovieRate = 32768;        // speed up rate to 1/2 normal        
  795.  
  796. // Put the call back into call back chain ( and append newMovieRate )
  797.             hTempCallBackInfo = AddNewCallBackInfo( pWindow,
  798.                                                                                             theNewCallBack,
  799.                                                                                             (Ptr)&newMovieRate, sizeof ( long ),
  800.                                                                                             triggerTimeFwd,
  801.                                                                                             theCallBackOffset,
  802.                                                                                             (**hDocMovieInfo).moviesTimeScale  );
  803.     
  804. // Attach the call back to the movie's time structures
  805.             theErr = CallMeWhen ( theNewCallBack,
  806.                                                         gAlterRateUpp,
  807.                                                         (long)hTempCallBackInfo,
  808.                                                         (**hTempCallBackInfo).param1,
  809.                                                         (**hTempCallBackInfo).param2,
  810.                                                         (**hTempCallBackInfo).param3 );
  811.             if (theErr)
  812.                 ReportError( "\pError !! CallMeWhen", theErr );
  813.         }
  814.     }
  815.     return ( theErr );    
  816. }
  817.  
  818. //----------------------------------------------
  819. //  SetupLoop
  820. //
  821. // Set up a loop in the movie.
  822. // - It uses call backs, to change the position of
  823. //   the movie "loopWhen" seconds into it and moves it
  824. //   to "loopTo" seconds
  825. //----------------------------------------------
  826.  
  827. OSErr SetupLoop ( WindowPtr pWindow,
  828.                                     short    loopWhen,
  829.                                     short    loopTo  )
  830. {
  831.     OSErr  theErr = noErr;
  832.     DocMovieInfoHndl hDocMovieInfo; // Info about the windows movie
  833.     long                 callBackWhen;  // When we want to start loop
  834.     CallBackInfoHdl  hTempCallBackInfo; // Call back information
  835.     QTCallBack             tempCallBack;  // Call Back
  836.     TimeValue        newTimeValue;  // Where we want to loop to
  837.  
  838.     hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (pWindow);
  839.  
  840. // Calculate when the movie should 'jump'
  841.     callBackWhen = loopWhen*(**hDocMovieInfo).moviesTimeScale;
  842.  
  843. // Creates a call back
  844.     tempCallBack = NewCallBack((**hDocMovieInfo).moviesTimeBase, callBackAtTime);
  845.  
  846. // Set up where it's going to loop to
  847.     newTimeValue = loopTo * (**hDocMovieInfo).moviesTimeScale;
  848.  
  849. // Add the call back to the call back list
  850.     hTempCallBackInfo = AddNewCallBackInfo( pWindow,
  851.                                                                                     tempCallBack,
  852.                                                                                     (Ptr) &newTimeValue, sizeof ( TimeValue ),
  853.                                                                                     triggerTimeFwd,
  854.                                                                                     callBackWhen,
  855.                                                                                     (**hDocMovieInfo).moviesTimeScale  );
  856.  
  857. // Attach the call back to the movie's time structures
  858.     theErr = CallMeWhen( tempCallBack,
  859.                                              gAlterMasterOffsetUpp, (long)hTempCallBackInfo,
  860.                                             (**hTempCallBackInfo).param1,
  861.                                             (**hTempCallBackInfo).param2,
  862.                                             (**hTempCallBackInfo).param3 );
  863.  
  864.     return ( theErr );
  865. }
  866.  
  867. //----------------------------------------------
  868. // SetupSlaveMovie
  869. //
  870. // This sets up the slaved movie
  871. // - "slaveAheadBy" sets the duration that the
  872. //   slave  will lead the master (in seconds)
  873. // - "slaveDelayStart" sets the duration that the
  874. //   slave start will be delayed after the master starts
  875. // - If both values are set the same, the slave will start
  876. //   n seconds behind the master and run in sync
  877. //----------------------------------------------
  878.  
  879.  
  880. OSErr SetupSlaveMovie ( WindowPtr pMasterWindow,
  881.                                                 WindowPtr pSlaveWindow,
  882.                                                 short     slaveAheadBy,
  883.                                                 short     slaveDelayStart )
  884. {
  885.     OSErr                     theErr = noErr;
  886.     DocMovieInfoHndl hDocMasterInfo;  // masters info
  887.     DocMovieInfoHndl hDocSlaveInfo;   // slaves info
  888.     long             slaveTimeOffset; // difference between the two movies
  889.     long                 slaveStartDelay; // when we've got to start the slave
  890.     CallBackInfoHdl  hTempCallBackInfo; // Call back information
  891.     QTCallBack             tempCallBack;    // call back
  892.     Movie            movieToStart;    // Put into the call back
  893.     TimeValue               theMovieLen;     // Length of the movie
  894.  
  895. // Get the info about the two movies
  896.     hDocMasterInfo = (DocMovieInfoHndl)GetWRefCon (pMasterWindow);
  897.     hDocSlaveInfo  = (DocMovieInfoHndl)GetWRefCon (pSlaveWindow);
  898.  
  899. // Attach the slave window onto the master
  900.     (**hDocMasterInfo).pSlaveWind = pSlaveWindow;
  901.  
  902. // Set the master movies time base value
  903.     SetTimeBaseValue((**hDocMasterInfo).moviesTimeBase,0,(**hDocMasterInfo).moviesTimeScale);
  904.  
  905. // slave second movie to first
  906.     SetMovieMasterTimeBase( (**hDocSlaveInfo).actualMovie,
  907.                                                     (**hDocMasterInfo).moviesTimeBase,
  908.                                                     nil );
  909.  
  910. // --- Setup the slave so it will lead the master ---
  911.     if (slaveAheadBy != kInSync)
  912.     {
  913. // Calculate how big the offset should be
  914.         if (slaveAheadBy == kOneThird)
  915.         {
  916.     // get the movie's length
  917.             theMovieLen  = GetMovieDuration((**hDocSlaveInfo).actualMovie);
  918.             slaveTimeOffset  = theMovieLen*0.3333;
  919.         }
  920.         else
  921.             slaveTimeOffset  = slaveAheadBy*(**hDocMasterInfo).moviesTimeScale;
  922.             
  923. // Set the slaves time base offset
  924.         SetTimeBaseValue( (**hDocSlaveInfo).moviesTimeBase,
  925.                                             slaveTimeOffset,
  926.                                             (**hDocSlaveInfo).moviesTimeScale);
  927.         theErr = GetAndReportError( "\pError !! - Offsetting timebase" );
  928.     }
  929.  
  930. // --- Put in the call back to start the slave movie (delayed if requested )--
  931.  
  932. // Set up slaveStartDelay
  933.     if (slaveDelayStart == kInSync)
  934.         slaveStartDelay = 0;
  935.     else
  936.         if (slaveDelayStart == kOneThird)
  937.         {
  938.     // get the movie's length
  939.             theMovieLen  = GetMovieDuration((**hDocMasterInfo).actualMovie);
  940.             slaveStartDelay = theMovieLen*0.3333;
  941.         }
  942.         else
  943.             slaveStartDelay = slaveDelayStart * (**hDocMasterInfo).moviesTimeScale;
  944.  
  945. // Create a new call back
  946.     tempCallBack = NewCallBack((**hDocMasterInfo).moviesTimeBase,callBackAtTime);
  947.  
  948. // Link the call back into the chain
  949.     movieToStart = (**hDocSlaveInfo).actualMovie;
  950.     hTempCallBackInfo = AddNewCallBackInfo( pMasterWindow,
  951.                                                                                     tempCallBack,
  952.                                                                                     (Ptr) &movieToStart, sizeof(Movie),
  953.                                                                                     triggerTimeFwd,
  954.                                                                                     slaveStartDelay,
  955.                                                                                     (**hDocMasterInfo).moviesTimeScale  );
  956.  
  957. // Attach the call back to the movie's time structures
  958.     theErr = CallMeWhen ( tempCallBack, gStartMovieCBUpp,
  959.                                                 (long)hTempCallBackInfo,
  960.                                                 (**hTempCallBackInfo).param1,
  961.                                                 (**hTempCallBackInfo).param2,
  962.                                                 (**hTempCallBackInfo).param3 );
  963.  
  964.     ReportError( "\pError!! - Creating movie start call back", theErr );
  965.  
  966.     return ( theErr );    
  967. }
  968.  
  969.  
  970. //----------------------------------------------
  971. // StartMovieWindow
  972. //
  973. // Start a movie in pWindow
  974. //----------------------------------------------
  975. OSErr StartMovieWindow( WindowPtr pWindow,
  976.                                                 Boolean   fromBegining  )
  977. {
  978.     DocMovieInfoHndl hDocMovieInfo;
  979.     
  980.     if (pWindow)
  981.     {
  982.         hDocMovieInfo = (DocMovieInfoHndl)GetWRefCon (pWindow);
  983.  
  984. // Set up the movie and start it
  985.         if (fromBegining)
  986.             GoToBeginningOfMovie((**hDocMovieInfo).actualMovie);
  987.  
  988.         SetMovieActive((**hDocMovieInfo).actualMovie,true);
  989.         StartMovie((**hDocMovieInfo).actualMovie);
  990.     }
  991.     return( noErr );
  992. }
  993.  
  994.